package com.sneakxy.corodova.plugin.baidulbs;

import android.Manifest.permission;
import android.content.pm.PackageManager;

import com.baidu.location.BDAbstractLocationListener;
import com.baidu.location.BDLocation;
import com.baidu.location.LocationClient;
import com.baidu.location.LocationClientOption;

import org.apache.cordova.CordovaInterface;
import org.apache.cordova.CordovaPlugin;
import org.apache.cordova.CallbackContext;

import org.apache.cordova.CordovaWebView;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;

import java.util.ArrayList;
import java.util.List;

/**
 * This class echoes a string called from JavaScript.
 */
public class CordovaPluginBaidulbs extends CordovaPlugin {

    public static final int SUCCESS = 0;

    public static final int PERMISSION_DENIED = 1;

    public static final int POSITION_UNAVAILABLE = 2;

    public static final int TIMEOUT = 3;

    public static final int UNKNOWN_ERROR = 4;

    public static final String NAME_CODE = "code";

    public static final int PERMISSION_CODE = 1289;

    private CallbackContext currentCallbackContext;

    private LocationClient locationClient;

    public static final String[] PERMISSIONS = new String[] {
            permission.ACCESS_COARSE_LOCATION,
            permission.ACCESS_FINE_LOCATION,
            permission.ACCESS_WIFI_STATE,
            permission.ACCESS_NETWORK_STATE,
            permission.CHANGE_WIFI_STATE,
            permission.WRITE_EXTERNAL_STORAGE,
            permission.INTERNET
    };

    @Override
    public void initialize(CordovaInterface cordova, CordovaWebView webView) {
        locationClient = new LocationClient(webView.getContext());
        LocationClientOption option = new LocationClientOption();

        option.setLocationMode(LocationClientOption.LocationMode.Hight_Accuracy);
        //可选，设置定位模式，默认高精度
        //LocationMode.Hight_Accuracy：高精度；
        //LocationMode. Battery_Saving：低功耗；
        //LocationMode. Device_Sensors：仅使用设备；

        option.setCoorType("BD09ll");
        //可选，设置返回经纬度坐标类型，默认GCJ02
        //GCJ02：国测局坐标；
        //BD09ll：百度经纬度坐标；
        //BD09：百度墨卡托坐标；
        //海外地区定位，无需设置坐标类型，统一返回WGS84类型坐标

        option.setScanSpan(1000);
        //可选，设置发起定位请求的间隔，int类型，单位ms
        //如果设置为0，则代表单次定位，即仅定位一次，默认为0
        //如果设置非0，需设置1000ms以上才有效

        option.setOpenGps(true);
        //可选，设置是否使用gps，默认false
        //使用高精度和仅用设备两种定位模式的，参数必须设置为true

        option.setLocationNotify(false);
        //可选，设置是否当GPS有效时按照1S/1次频率输出GPS结果，默认false

        option.setIgnoreKillProcess(false);
        //可选，定位SDK内部是一个service，并放到了独立进程。
        //设置是否在stop的时候杀死这个进程，默认（建议）不杀死，即setIgnoreKillProcess(true)

        option.SetIgnoreCacheException(false);
        //可选，设置是否收集Crash信息，默认收集，即参数为false

        option.setWifiCacheTimeOut(5*60*1000);
        //可选，V7.2版本新增能力
        //如果设置了该接口，首次启动定位时，会先判断当前Wi-Fi是否超出有效期，若超出有效期，会先重新扫描Wi-Fi，然后定位

        option.setEnableSimulateGps(false);
        //可选，设置是否需要过滤GPS仿真结果，默认需要，即参数为false

        option.setNeedNewVersionRgc(true);
        //可选，设置是否需要最新版本的地址信息。默认需要，即参数为true

        locationClient.setLocOption(option);
    }

    public class BaidulbsLocationListener extends BDAbstractLocationListener {

        private CallbackContext callbackContext;

        private CordovaPluginBaidulbs cordovaPluginBaidulbs;

        public BaidulbsLocationListener(CordovaPluginBaidulbs cordovaPluginBaidulbs, CallbackContext callbackContext) {
            this.cordovaPluginBaidulbs = cordovaPluginBaidulbs;
            this.callbackContext = callbackContext;
        }

        @Override
        public void onReceiveLocation(BDLocation location) {
            this.cordovaPluginBaidulbs.getLocationClient().stop();
            this.cordovaPluginBaidulbs.getLocationClient().unRegisterLocationListener(this);
            try {

                double latitude = location.getLatitude();    //获取纬度信息
                double longitude = location.getLongitude();    //获取经度信息
                JSONObject result = new JSONObject();
                result.put("code", SUCCESS);

                JSONObject coords = new JSONObject();
                coords.put("longitude", longitude);
                coords.put("latitude", latitude);

                result.put("coords", coords);
                result.put("city", location.getCity());
                result.put("cityCode", location.getCityCode());
                callbackContext.success(result);
            } catch (JSONException e) {
                e.printStackTrace();
            }
        }
    }

    @Override
    public boolean execute(String action, JSONArray args, CallbackContext callbackContext) throws JSONException {
        if (action.equals("getCurrentPosition")) {
            this.getCurrentPosition(callbackContext);
            return true;
        }
        return false;
    }

    private void getCurrentPosition(CallbackContext callbackContext) throws JSONException {
        if(this.hasPermisssion()) {
            fetchBaiduPosition(callbackContext);
        } else {
            this.currentCallbackContext = callbackContext;
            this.requestPermissions(PERMISSION_CODE);
        }
    }

    protected void fetchBaiduPosition(CallbackContext callbackContext) {
        locationClient.registerLocationListener(new BaidulbsLocationListener(this, callbackContext));
        locationClient.start();
    }

    @Override
    public boolean hasPermisssion() {
        for(String perm: PERMISSIONS) {
            if(!cordova.hasPermission(perm)) {
                return false;
            }
        }
        return true;
    }

    @Override
    public void requestPermissions(int requestCode) {
        List<String> list = new ArrayList<>();
        for(String perm: PERMISSIONS) {
            if(!cordova.hasPermission(perm)) {
                list.add(perm);
            }
        }
        cordova.requestPermissions(this, requestCode, list.toArray(new String[] {}));
    }

    @Override
    public void onRequestPermissionResult(int requestCode, String[] permissions, int[] grantResults) throws JSONException {
        if(PERMISSION_CODE == requestCode) {
            for(int i=0; i<permissions.length; i++) {
                if(PackageManager.PERMISSION_DENIED == grantResults[i]) {
                    if(currentCallbackContext != null) {
                        currentCallbackContext.error(error(PERMISSION_DENIED));
                        currentCallbackContext = null;
                    }
                    return;
                }
            }
            if(currentCallbackContext != null) {
                fetchBaiduPosition(currentCallbackContext);
                currentCallbackContext = null;
            }
        }
    }

    public JSONObject error(int code) throws JSONException {
        JSONObject error = new JSONObject();
        error.put("PERMISSION_DENIED", PERMISSION_DENIED);
        error.put("POSITION_UNAVAILABLE", POSITION_UNAVAILABLE);
        error.put("TIMEOUT", TIMEOUT);
        error.put("UNKNOWN_ERROR", UNKNOWN_ERROR);
        error.put(NAME_CODE, code);
        return error;
    }

    public LocationClient getLocationClient() {
        return this.locationClient;
    }

}
